﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.Diagnostics;

namespace Aphysoft.Vate
{
    public partial class Vate
    {
        #region Properties

        /// <summary>
        /// Internal Game time, in seconds.
        /// </summary>
        private static double gameTime = 0f;
        /// <summary>
        /// Gets internal game time counter, in seconds.
        /// </summary>
        public static double GameTime
        {
            get { return Vate.gameTime; }
        }
        /// <summary>
        /// Elapsed time, in milliseconds, between current frame and last frame.
        /// </summary>
        private static float elapsedTime = 0f;
        /// <summary>
        /// Gets elapsed time, in milliseconds, between current frame and last frame.
        /// </summary>
        public static float ElapsedTime
        {
            get 
            {
#if PRERENDERED
                if (PreRenderedHelper.Active)
                    return PreRenderedHelper.ElapsedTime;
#endif
                return elapsedTime; 
            }
        }
        /// <summary>
        /// Time speed.
        /// </summary>
        private static float timeSpeed = 1f;
        /// <summary>
        /// Gets or sets time
        /// </summary>
        public static float TimeSpeed
        {
            get { return timeSpeed; }
            set { timeSpeed = MathHelper.Clamp(value, 0, 2); }
        }
        /// <summary>
        /// Gets time factor per second, multiply every time related update to this properties. 
        /// When we got 1 fps, this will be 1.0f, when we got 100 fps, this will be 0.01f.
        /// All if time speed is 1.0f.
        /// </summary>
        public static float TimeFactor
        {
            get 
            {
#if PRERENDERED
                if (PreRenderedHelper.Active)
                    return PreRenderedHelper.ElapsedTime * timeSpeed;
#endif

                return ((float)ElapsedTime / 1000.0f) * timeSpeed; 
            }
        }
        /// <summary>
        /// Fps.
        /// </summary>
        private static int fpsLastSecond = 60;
        /// <summary>
        /// Frame Per Seconds.
        /// </summary>
        public static int Fps
        {
            get 
            {
                return fpsLastSecond; 
            }
        }
        /// <summary>
        /// Frame counter.
        /// </summary>
        private static int frameCounter = 0;
        /// <summary>
        /// Frame counter helper, elapsed time.
        /// </summary>
        private static TimeSpan frameElapsedTime = TimeSpan.Zero;

        /// <summary>
        /// Target frame per second for testing performance.
        /// </summary>
        private static int targetFps = 1000;
        /// <summary>
        /// Gets or sets a value for desired Frame Per Seconds.
        /// </summary>
        public static int TargetFps
        {
            get { return targetFps; }
            set { targetFps = value; }
        }
        /// <summary>
        /// Input triangle count.
        /// </summary>
        private static int inputTriangle = 0;
        /// <summary>
        /// Gets input triangle count.
        /// </summary>
        public static int InputTriangle
        {
            get { return inputTriangle; }
        }       
        /// <summary>
        /// Built in internal counter when Vate used by vate studio.
        /// </summary>
        private static Stopwatch stopwatch = null;

        #endregion

        #region Methods
        /// <summary>
        /// Game time calculation in update section. Internal use only.
        /// </summary>
        public static void TimeUpdate(GameTime gameTime)
        {
            // acquires elapsed time between frame.
            if (gameTime == null)
            {
                double elapsedTimeInSecond = 0;

                if (stopwatch == null)
                {
                    stopwatch = new Stopwatch();                    
                }

                if (stopwatch.IsRunning)
                {
                    stopwatch.Stop();
                    frameElapsedTime += stopwatch.Elapsed;
                    elapsedTime = (float)stopwatch.Elapsed.TotalMilliseconds;
                    elapsedTimeInSecond = stopwatch.Elapsed.TotalSeconds;
                    stopwatch.Reset();
                }
                stopwatch.Start();

                if (frameElapsedTime > TimeSpan.FromSeconds(1))
                {
                    frameElapsedTime -= TimeSpan.FromSeconds(1);
                    fpsLastSecond = frameCounter;
                    frameCounter = 0;
                }

                Vate.gameTime += elapsedTimeInSecond;
            }
            else
            {
                double elapsedTimeInSecond;

#if PRERENDERED
                if (PreRenderedHelper.Active)
                {                    
                    elapsedTime = PreRenderedHelper.ElapsedTime / 1000.0f;
                    elapsedTimeInSecond = PreRenderedHelper.ElapsedTime;
                    frameElapsedTime += new TimeSpan(0, 0, 0, 0, (int)elapsedTime);
                }
                else
                {
#endif
                    frameElapsedTime += gameTime.ElapsedGameTime;
                    elapsedTime = (float)gameTime.ElapsedGameTime.TotalMilliseconds;
                    elapsedTimeInSecond = gameTime.ElapsedGameTime.TotalSeconds;
#if PRERENDERED
                }
#endif
 
                if (frameElapsedTime > TimeSpan.FromSeconds(1))
                {
                    frameElapsedTime -= TimeSpan.FromSeconds(1);
                    fpsLastSecond = frameCounter;
                    frameCounter = 0;
                }

                Vate.gameTime += elapsedTimeInSecond;
            }
        }
        /// <summary>
        /// Game time calculation in draw section. Internal use only.
        /// </summary>
        /// <param name="gameTime"></param>
        public static void TimeDraw(GameTime gameTime)
        {
            frameCounter++;
        }

        /// <summary>
        /// Add triangle counter for benchmarking.
        /// </summary>
        /// <param name="n">Triangle count.</param>
        public static void AddInputTriangle(int n)
        {
#if DEBUG
            inputTriangle += n;
#endif
        }
        /// <summary>
        /// Resets triangle counter. Internal use only.
        /// </summary>
        public static void ResetInputTriangle()
        {
#if DEBUG
            inputTriangle = 0;
#endif
        }
        /// <summary>
        /// Multiply specified value by TimeFactor.
        /// </summary>
        /// <param name="value">A float value.</param>
        public static float Time(float value)
        {
            return TimeFactor * value;
        }
        /// <summary>
        /// Multiply specified value by TimeFactor.
        /// </summary>
        /// <param name="value">A integer value.</param>
        public static float Time(int value)
        {
            return TimeFactor * value;
        }
        #endregion
    }
}
